之前,我跟朋友介紹 Datomic 時,有一些朋友會在第一時間反問:
你講的這個資料庫是 SQL 還是 noSQL ?
我通常是這樣子回答:
既然是設計來取代 SQL 資料庫的,那 SQL 資料庫有什麼共同的設計缺陷嗎?有的,而且還不少。只是說,由於有很多缺陷都已經有了所謂的權宜之計 (workaround),久了,大家也就久而不聞其臭,當作這是自然的現象。
以下列出幾項值得討論的缺陷:
假設你在經營一間水果行,8/1 開店時庫存資料庫的狀態如下:
id | 產品 | 存量 |
---|---|---|
1 | 蘋果 | 100 |
2 | 橘子 | 200 |
8/1 一整天銷售了 60 顆蘋果。於是, 8/2 開店時庫存如下:
id | 產品 | 存量 |
---|---|---|
1 | 蘋果 | 40 |
2 | 橘子 | 200 |
於是,到了月底 8/31 時,我們臨時想要知道月初時的庫存,很遺憾,辦不到。
因為如果沒有特別把資料存下來的話,SQL 資料庫沒有辦法像版本控管軟體一樣,做到先前狀態的回溯。
對 SQL 有點熟悉度的讀者可能心想,咦,這有什麼問題嗎?像下方的 SQL 查詢,不是也都使用了好多年,滿順手的啊?
SELECT *
FROM table_name
WHERE column_A = 5;
像上述的查詢,如果可以更改設計,改成資料結構型態的查詢語言,就會好得多,比方說:
{:select :*
:from "table_name"
:where [:= "column_A" 5]}
在解釋為何字串型態的查詢語言不佳之前,我們需要先定義一個詞彙:『資料結構』(data structure)
在傳統的資訊工程課程,資料結構是指:雜湊 (hash)、堆積 (heap)、樹 (tree) 、堆疊 (stack)、佇列 (queue) 等東西,重點著重在於不同的儲存資料方式會有不同的效能特性。然而,在程式語言的領域,資料結構則是指:集合、向量、字典,此處的重點則著重在於程式語言所提供的表示法。
以 Clojure 語言為例:
#{:a :b :c}
[:a :b :c]
{:a "hello" :b 15}
比較前述 SQL 查詢的兩種表示法之後,我們可以自問兩個問題:
以 SQL 查詢為例,通常凡是程式語言的字串,它都內含有所謂的語法樹 (syntax tree)。學會寫 SQL 的同時,這個語法樹的概念也就自然地內建到寫作者的腦海中,然而,更直接的方式,是在寫查詢語言時,就透過資料結構型態來呈現語法樹,讓重要的概念更加明顯,所以是資料結構型態更容易看得懂。
此外,讀者可以仔細觀察,在資料結構型態的表示法裡,字串、整數都需要清楚地寫出來,而在上頭的例子裡的字串 "column_A"
、例子裡的整數 5
,這兩個值的資料型態也都會被編譯器檢查。
現在,多數的程式語言都提供強大的資料結構操作函式庫。換言之,如果今天我們需要寫另一個查詢,它的判斷條件需要做一些變化,需要是第 B
欄的值恰好為 16
。
{:select :*
:from "table_name"
:where [:= "column_B" 16]}
如果是用 Clojure 語言來做操作的話,我們可以寫成:
(def old-query
{:select :*
:from "table_name"
:where [:= "column_A" 5]})
(def new-query
(assoc old-query :where [:= "column_B" 16]))
(prn new-query)
;; =>
;; {:select :*
;; :from "table_name"
;; :where [:= "column_B" 16]}
(assoc old-query :where [:= "column_B" 16])
的這一小段 code snippet
,就可以將 new-query
的內容做出。
其它資源: